// Package article
// Created by GoLand
// @User: lenora
// @Date: 2024/2/14
// @Time: 15:07

package article

import (
	"context"
	"github.com/bwmarrin/snowflake"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"time"
)

func NewMongoDBArticleDao(db *mongo.Database, node *snowflake.Node) ArticleDao {
	return &MongoDBArticleDao{
		node:   node,
		col:    db.Collection("article"),
		proCol: db.Collection("published_article"),
	}
}

type MongoDBArticleDao struct {
	node   *snowflake.Node
	col    *mongo.Collection
	proCol *mongo.Collection
}

func (dao *MongoDBArticleDao) ListByOffset(ctx context.Context, start time.Time, offset, size int) ([]Articles, error) {
	//TODO implement me
	panic("implement me")
}

func (dao *MongoDBArticleDao) GetByAuthor(ctx context.Context, uid uint64, offset, limit int) ([]Articles, error) {
	//TODO implement me
	panic("implement me")
}

func (dao *MongoDBArticleDao) GetById(ctx context.Context, id uint64) (Articles, error) {
	//TODO implement me
	panic("implement me")
}

func (dao *MongoDBArticleDao) Insert(ctx context.Context, art Articles) (uint64, error) {
	now := time.Now().UnixMilli()
	art.Ctime = now
	art.Utime = now
	art.Id = uint64(dao.node.Generate())
	_, err := dao.col.InsertOne(ctx, art)
	return art.Id, err
}

func (dao *MongoDBArticleDao) UpdateById(ctx context.Context, art Articles) error {
	filter := bson.D{
		bson.E{"id", art.Id},
		bson.E{"creator", art.Creator},
	}
	set := bson.D{bson.E{"$set", bson.M{
		"title":   art.Title,
		"content": art.Content,
		"status":  art.Status,
		"utime":   time.Now().UnixMilli(),
	}}}
	res, err := dao.col.UpdateOne(ctx, filter, set)
	if err != nil {
		return err
	}
	if res.ModifiedCount == 0 {
		return mongo.ErrNoDocuments
	}
	return nil
}

func (dao *MongoDBArticleDao) Sync(ctx context.Context, art Articles) (uint64, error) {
	var (
		id  = art.Id
		err error
	)
	if art.Id == 0 {
		id, err = dao.Insert(ctx, art)
	} else {
		err = dao.UpdateById(ctx, art)
	}

	if err != nil {
		return 0, err
	}

	art.Id = id
	now := time.Now().UnixMilli()
	art.Utime = now
	filter := bson.D{
		bson.E{"id", art.Id},
		bson.E{"creator", art.Creator},
	}
	set := bson.D{
		bson.E{"$set", art},
		bson.E{"$setOnInsert", bson.D{bson.E{"ctime", now}}},
	}
	_, err = dao.proCol.UpdateOne(ctx, filter, set, options.Update().SetUpsert(true))
	return id, err
}

func (dao *MongoDBArticleDao) SyncStatus(ctx context.Context, uid, id uint64, status uint8) error {
	filter := bson.D{
		bson.E{"id", id},
		bson.E{"creator", uid},
	}
	set := bson.D{bson.E{"$set", bson.M{
		"status": status,
		"utime":  time.Now().UnixMilli(),
	}}}
	res, err := dao.col.UpdateOne(ctx, filter, set)
	if err != nil {
		return err
	}
	if res.ModifiedCount == 0 {
		return mongo.ErrNoDocuments
	}
	_, err = dao.proCol.UpdateOne(ctx, filter, set)
	return err
}
